#include "RdfStore.h"


RdfStore::RdfStore(){
    /*
     * Initialize
     */
	world=NULL;
	model=NULL;
	context_node=NULL;
	node=NULL;
    /*
     * 初始化与存储相关的资源
     */

    storage=NULL;
    options=NULL;
	counter = -1;
	std::cout << "create store " << counter << " done!" << std::endl;
    storage_name="sqlite";
    context="http://red";

    node_identifier = "toSend/semantic_All.db";

	identifier = node_identifier.c_str();

	world = librdf_new_world();

	librdf_world_open(world);

	options = librdf_new_hash(world, NULL);

	librdf_hash_put_strings(options, "new", "yes");

	transactions = 1;
	storage = librdf_new_storage_with_options(world, storage_name,
			identifier, options);

	if (!storage) {
		fprintf(stderr, ": Failed to open %s storage '%s'\n", storage_name,
				identifier);
	}

	model = librdf_new_model(world, storage, NULL);

	if (!model) {
		fprintf(stderr, ": Failed to create model\n");
	}

//	if (transactions)
	  librdf_model_transaction_start(model);

		/* Do this or gcc moans */
//	  context_node= librdf_new_node_from_uri_string(world,
//		  (const unsigned char *) context);
//
//	  librdf_model_context_remove_statements(model, context_node);//将数据库内的数据全部清除

}

RdfStore::RdfStore(std::string option){
    /*
     * Initialize
     */
	world=NULL;
	model=NULL;
	context_node=NULL;
	node=NULL;
    /*
     * 初始化与存储相关的资源
     */

    storage=NULL;
    options=NULL;
	counter = -1;
	std::cout << "create store " << counter << " done!" << std::endl;
    storage_name="sqlite";
    context="http://red";

    node_identifier = "toSend/semantic_All.db";

	identifier = node_identifier.c_str();

	world = librdf_new_world();

	librdf_world_open(world);

	options = librdf_new_hash(world, NULL);

	librdf_hash_put_strings(options, "new", "yes");

	transactions = 1;

	std::string newOption="new";
	if(!option.compare(newOption))
	storage = librdf_new_storage_with_options(world, storage_name,
			identifier, options);
	else{
	storage = librdf_new_storage(world,storage_name,identifier,NULL);
	std::cout << "Open the storage without new!" << std::endl;
	}

	if (!storage) {
		fprintf(stderr, ": Failed to open %s storage '%s'\n", storage_name,
				identifier);
	}

	model = librdf_new_model(world, storage, NULL);

	if (!model) {
		fprintf(stderr, ": Failed to create model\n");
	}

//	if (transactions)
	  librdf_model_transaction_start(model);

		/* Do this or gcc moans */
//	  context_node= librdf_new_node_from_uri_string(world,
//		  (const unsigned char *) context);
//
//	  librdf_model_context_remove_statements(model, context_node);//将数据库内的数据全部清除

}


RdfStore::RdfStore(std::string option,std::string database_Name){
    /*
     * Initialize
     */
	world=NULL;
	model=NULL;
	context_node=NULL;
	node=NULL;
    /*
     * 初始化与存储相关的资源
     */

    storage=NULL;
    options=NULL;
	counter = -1;
	std::cout << "create store " << counter << " done!" << std::endl;
    storage_name="sqlite";
    context="http://red";

    node_identifier = database_Name;//"toSend/semantic_All.db";

	identifier = node_identifier.c_str();

	world = librdf_new_world();

	librdf_world_open(world);

	options = librdf_new_hash(world, NULL);

	librdf_hash_put_strings(options, "new", "yes");

	transactions = 1;

	std::string newOption="new";
	if(!option.compare(newOption))
	storage = librdf_new_storage_with_options(world, storage_name,
			identifier, options);
	else{
	storage = librdf_new_storage(world,storage_name,identifier,NULL);
	std::cout << "Open the storage without new!" << std::endl;
	}

	if (!storage) {
		fprintf(stderr, ": Failed to open %s storage '%s'\n", storage_name,
				identifier);
	}

	model = librdf_new_model(world, storage, NULL);

	if (!model) {
		fprintf(stderr, ": Failed to create model\n");
	}

//	if (transactions)
	  librdf_model_transaction_start(model);

		/* Do this or gcc moans */
//	  context_node= librdf_new_node_from_uri_string(world,
//		  (const unsigned char *) context);
//
//	  librdf_model_context_remove_statements(model, context_node);//将数据库内的数据全部清除

}

RdfStore::RdfStore(int i){
    /*
     * Initialize
     */
	world=NULL;
	model=NULL;
	context_node=NULL;
	node=NULL;
    /*
     * 初始化与存储相关的资源
     */

    storage=NULL;
    options=NULL;



	counter = i;
	std::cout << "create store " << counter << " done!" << std::endl;
    storage_name="sqlite";
    context="http://red";

	std::ostringstream nodeID_s[3];

	int nodeID_i[3];

	nodeID_i[0] = i % 3;
	nodeID_i[1] = (i/3) % 3;
	nodeID_i[2] = (i/9) % 3;

   	for(int index=0; index<3; index++)
    		nodeID_s[index] << nodeID_i[index];

    	node_identifier = "toSend/semantic_node_" + nodeID_s[2].str() + "_" + nodeID_s[1].str() + "_" + nodeID_s[0].str() +".db";

	identifier = node_identifier.c_str();

	world = librdf_new_world();

	librdf_world_open(world);

	options = librdf_new_hash(world, NULL);

	librdf_hash_put_strings(options, "new", "yes");

	transactions = 1;
	storage = librdf_new_storage_with_options(world, storage_name,
			identifier, options);

	if (!storage) {
		fprintf(stderr, ": Failed to open %s storage '%s'\n", storage_name,
				identifier);
	}

	model = librdf_new_model(world, storage, NULL);

	if (!model) {
		fprintf(stderr, ": Failed to create model\n");
	}

//	if (transactions)
	  librdf_model_transaction_start(model);
}

int RdfStore::store_triple(const char *s, const char *p, const char *o){
	  librdf_node *subject, *predicate, *object;
	  librdf_statement* statement=NULL;
	  int rc;

	  subject=librdf_new_node_from_uri_string(world, (const unsigned char *)s);
	  predicate=librdf_new_node_from_uri_string(world, (const unsigned char *)p);
	  object=librdf_new_node_from_uri_string(world, (const unsigned char *)o);

	  statement=librdf_new_statement(world);
	  librdf_statement_set_subject(statement, subject);
	  librdf_statement_set_predicate(statement, predicate);
	  librdf_statement_set_object(statement, object);

	  rc=librdf_model_context_add_statement(model, context_node, statement);

	  librdf_free_statement(statement);

	  librdf_model_transaction_commit(model);
	  return rc;
}




RdfStore::~RdfStore(){
	std::cout << "deleting rdfstore " << counter << std::endl;
	if(options){
		std::cout << "deleting options done!"  << std::endl;
		librdf_free_hash(options);
	}
	if(context_node){
		std::cout << "deleting context_node done!"  << std::endl;
		librdf_free_node(context_node);
	}
	if(model){
		std::cout << "deleting model done!"  << std::endl;
		librdf_free_model(model);
	}
	if(storage){
		std::cout << "deleting storage done!"  << std::endl;
		librdf_free_storage(storage);
	}
	if(world){
		std::cout << "deleting world done!"  << std::endl;
		librdf_free_world(world);
	}
}



void RdfStore::clean_storage(){
	/* Do this or gcc moans */
  context_node= librdf_new_node_from_uri_string(world,
	  (const unsigned char *) context);

  librdf_model_context_remove_statements(model, context_node);//将数据库内的数据全部清除
}

void RdfStore::exec_query(std::string query){
	subquery=NULL;
//	std::cout << query << std::endl;
	subquery = librdf_new_query(world, (char *) "sparql", NULL,(const unsigned char *)(query.c_str()), NULL);
	if (!(results = librdf_model_query_execute(model, subquery))) {
		std::cout << "librdf_model_query_execute is error!" << std::endl;
		librdf_free_query(subquery);
		subquery = NULL;
	} else {
		print_query_results(world, model, results);
		librdf_free_query_results(results);
	}
	librdf_free_query(subquery);
}

int RdfStore::print_query_results(librdf_world* world, librdf_model* model, librdf_query_results *results)
{
    int i;
    char *name;
    librdf_stream* stream=NULL;
    librdf_serializer* serializer=NULL;
    const char *query_graph_serializer_syntax_name="rdfxml";

//	QFile resultFile("resultFile/ResultS.txt");			//将结果保存在文件中
//	if(!resultFile.open(QIODevice::WriteOnly)){
//		std::cout << "error creating file ResultS.txt[in RdfStore::print_query_results]" <<std::endl;
//	}

    if(librdf_query_results_is_bindings(results)) {
        fprintf(stdout, ": Query returned bindings results:\n");

    while(!librdf_query_results_finished(results)) {
        NTuple answer;
//        fputs("result: [", stdout);
//      resultFile.write("[");		//将结果保存在文件中
        for(i=0; i<librdf_query_results_get_bindings_count(results); i++) {
            Binding binding;
            std::string name_str;
            librdf_node *value=librdf_query_results_get_binding_value(results, i);
    	    name=(char*)librdf_query_results_get_binding_name(results, i);
    	    name_str=name;
//	        if(i>0){
//	           fputs(", ", stdout);
//	           resultFile.write(", ");//将结果保存在文件中
//	        }
//	        fprintf(stdout, "%s=", name);
    	    binding.setVariableName(name_str);
//	        resultFile.write(name);//将结果保存在文件中
//	        resultFile.write("=");//将结果保存在文件中
	        if(value) {
//	            librdf_node_print(value, stdout);
	            librdf_node_print2(value, stdout, binding.value);//在此处将结果的值保存
//	            librdf_node_print3(value, stdout, resultFile);//将结果保存在文件中
	            librdf_free_node(value);
	        } else{
//	            fputs("NULL", stdout);
//	            resultFile.write("NULL");      //将结果保存在文件中
	            binding.setValue("NULL");
	        }
	       answer.addBinding(binding);
        }
//      fputs("]\n", stdout);
//    resultFile.write("]\n");//将结果保存在文件中
      partialResult.push_back(answer);
      librdf_query_results_next(results);
    }
//    resultFile.close();
    fprintf(stdout, ": Query returned %d results\n", librdf_query_results_get_count(results));
  } else if(librdf_query_results_is_boolean(results)) {
    fprintf(stdout, ": Query returned boolean result: %s\n", librdf_query_results_get_boolean(results) ? "true" : "false");
    bool_ans=librdf_query_results_get_boolean(results) ? "true" : "false";
  } else if(librdf_query_results_is_graph(results)) {
    librdf_storage* tmp_storage =NULL;
    librdf_model* tmp_model = NULL;

    tmp_storage=librdf_new_storage(world, NULL, NULL, NULL);
    tmp_model=librdf_new_model(world, tmp_storage, NULL);

    fprintf(stdout, ": Query returned graph result:\n");

    stream=librdf_query_results_as_stream(results);
    if(!stream) {
      fprintf(stderr, ": Failed to get query results graph\n");
      return -1;
    }
    librdf_model_add_statements(tmp_model, stream);
    librdf_free_stream(stream);

    fprintf(stdout, ": Total %d triples\n", librdf_model_size(model));

    serializer=librdf_new_serializer(world, query_graph_serializer_syntax_name, NULL, NULL);
    if(!serializer) {
      fprintf(stderr, ": Failed to create serializer type %s\n", query_graph_serializer_syntax_name);
      return -1;
    }

    librdf_serializer_serialize_model_to_file_handle(serializer, stdout, NULL, tmp_model);
    librdf_free_serializer(serializer);
    librdf_free_model(tmp_model);
    librdf_free_storage(tmp_storage);
  } else {
    fprintf(stdout, ": Query returned unknown result format\n");
    return -1;
  }
  return 0;
}

/**
 * librdf_node_print:
 * @node: the node
 * @fh: file handle
 *
 * Pretty print the node to a file descriptor.
 *
 * This method is for debugging and the format of the output should
 * not be relied on.
 *
 **/
void	RdfStore::librdf_node_print2(librdf_node *node, FILE *fh,std::string &result)
{
  raptor_iostream *iostr;

//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN(node, librdf_node);
//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN(fh, FILE*);

  if(!node)
    return;

  iostr = raptor_new_iostream_to_file_handle(node->world, fh);
  if(!iostr)
    return;

  librdf_node_write2(node, iostr, result);

  raptor_free_iostream(iostr);
}


/**
 * librdf_node_print:
 * @node: the node
 * @fh: file handle
 *
 * Pretty print the node to a file descriptor.
 *
 * This method is for debugging and the format of the output should
 * not be relied on.
 *
 **/
void	RdfStore::librdf_node_print3(librdf_node *node, FILE *fh,QFile &resultFile)
{
  raptor_iostream *iostr;

//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN(node, librdf_node);
//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN(fh, FILE*);

  if(!node)
    return;

  iostr = raptor_new_iostream_to_file_handle(node->world, fh);
  if(!iostr)
    return;

  librdf_node_write3(node, iostr, resultFile);

  raptor_free_iostream(iostr);
}





/**
 * librdf_node_write:
 * @node: the node
 * @iostr: iostream to write to
 *
 * Write the node to an iostream in N-Triples format.
 *
 * This method can be used to write a node in a relatively
 * readable format.  To write more compact formats use a
 * serializer to pick a syntax and serialize triples to it.
 *
 * Return value: non-0 on failure
 **/
int RdfStore::librdf_node_write2(librdf_node* node, raptor_iostream *iostr, std::string &result)
{
  const unsigned char* term;
  size_t len;

#define NULL_STRING_LENGTH 6
  static const unsigned char * const null_string = (const unsigned char *)"(null)";

//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(iostr, raptor_iostream, 1);

  if(!node) {
    raptor_iostream_counted_string_write(null_string, NULL_STRING_LENGTH, iostr);
    return 0;
  }

  switch(node->type) {
    case RAPTOR_TERM_TYPE_LITERAL:
      raptor_iostream_write_byte('"', iostr);
      raptor_string_ntriples_write(node->value.literal.string,
                                   node->value.literal.string_len,
                                   '"',
                                   iostr);
      raptor_iostream_write_byte('"', iostr);
      if(node->value.literal.language) {
        raptor_iostream_write_byte('@', iostr);
        raptor_iostream_string_write(node->value.literal.language, iostr);
      }
      if(node->value.literal.datatype) {
        raptor_iostream_counted_string_write("^^<", 3, iostr);
        term = librdf_uri_as_counted_string(node->value.literal.datatype,
                                            &len);
        raptor_string_ntriples_write(term, len, '>', iostr);
        raptor_iostream_write_byte('>', iostr);
      }

      break;

    case RAPTOR_TERM_TYPE_BLANK:
      raptor_iostream_counted_string_write("_:", 2, iostr);
      term = (unsigned char*)node->value.blank.string;
      len = node->value.blank.string_len;
//      raptor_iostream_counted_string_write(term, len, iostr);
      break;

    case RAPTOR_TERM_TYPE_URI:
//      raptor_iostream_write_byte('<', iostr);
      term = librdf_uri_as_counted_string(node->value.uri, &len);
//      raptor_string_ntriples_write(term, len, '>', iostr);
//      raptor_iostream_write_byte('>', iostr);
      break;

    case RAPTOR_TERM_TYPE_UNKNOWN:
    default:
      /*LIBRDF_FATAL1(node->world, LIBRDF_FROM_NODE, "Unknown node type");*/
      return 1;
  }

  result = (const char*)term;
  return 0;
}


/**
 * librdf_node_write:
 * @node: the node
 * @iostr: iostream to write to
 *
 * Write the node to an iostream in N-Triples format.
 *
 * This method can be used to write a node in a relatively
 * readable format.  To write more compact formats use a
 * serializer to pick a syntax and serialize triples to it.
 *
 * Return value: non-0 on failure
 **/
int RdfStore::librdf_node_write3(librdf_node* node, raptor_iostream *iostr, QFile &resultFile)
{
  const unsigned char* term;
  size_t len;

#define NULL_STRING_LENGTH 6
  static const unsigned char * const null_string = (const unsigned char *)"(null)";

//  LIBRDF_ASSERT_OBJECT_POINTER_RETURN_VALUE(iostr, raptor_iostream, 1);

  if(!node) {
    raptor_iostream_counted_string_write(null_string, NULL_STRING_LENGTH, iostr);
    return 0;
  }

  switch(node->type) {
    case RAPTOR_TERM_TYPE_LITERAL:
      raptor_iostream_write_byte('"', iostr);
      raptor_string_ntriples_write(node->value.literal.string,
                                   node->value.literal.string_len,
                                   '"',
                                   iostr);
      raptor_iostream_write_byte('"', iostr);
      if(node->value.literal.language) {
        raptor_iostream_write_byte('@', iostr);
        raptor_iostream_string_write(node->value.literal.language, iostr);
      }
      if(node->value.literal.datatype) {
        raptor_iostream_counted_string_write("^^<", 3, iostr);
        term = librdf_uri_as_counted_string(node->value.literal.datatype,
                                            &len);
        raptor_string_ntriples_write(term, len, '>', iostr);
        raptor_iostream_write_byte('>', iostr);
      }

      break;

    case RAPTOR_TERM_TYPE_BLANK:
      raptor_iostream_counted_string_write("_:", 2, iostr);
      term = (unsigned char*)node->value.blank.string;
      len = node->value.blank.string_len;
      raptor_iostream_counted_string_write(term, len, iostr);
      break;

    case RAPTOR_TERM_TYPE_URI:
      raptor_iostream_write_byte('<', iostr);
      term = librdf_uri_as_counted_string(node->value.uri, &len);
      raptor_string_ntriples_write(term, len, '>', iostr);
      raptor_iostream_write_byte('>', iostr);
      break;

    case RAPTOR_TERM_TYPE_UNKNOWN:
    default:
      /*LIBRDF_FATAL1(node->world, LIBRDF_FROM_NODE, "Unknown node type");*/
      return 1;
  }

//  result = (const char*)term;
  resultFile.write((const char*)term);
  return 0;
}

std::vector<NTuple> RdfStore::getReault(){
	return partialResult;
}

std::string RdfStore::resultString(){
	std::string info;
	std::vector<NTuple>::iterator beg=partialResult.begin();
	std::vector<NTuple>::iterator end=partialResult.end();
	for(std::vector<NTuple>::iterator it=beg; it!=end; it++){
		info += it->toString();
	}
	return info;
}

bool RdfStore::containsAnyStatement(Statement statement){
	//创建ASK查询
	std::string query="ASK {";
	query += " <"+ statement.getSubject().getName() + "> ";
	query += " <"+ statement.getPredicate().getName() + "> ";
	query += " <"+ statement.getObject().getName()+ "> ";
	query += "}";
	subquery=NULL;
//	std::cout << query << std::endl;
	subquery = librdf_new_query(world, (char *) "sparql", NULL,(const unsigned char *)(query.c_str()), NULL);
	if (!(results = librdf_model_query_execute(model, subquery))) {
		std::cout << "librdf_model_query_execute is error!" << std::endl;
		librdf_free_query(subquery);
		subquery = NULL;
	} else {
		print_query_results(world, model, results);
		librdf_free_query_results(results);
	}
	librdf_free_query(subquery);
	return bool_ans.compare("true")?0:1;
}

void RdfStore::addStatement(Statement statement){
	std::string subject= statement.getSubject().getName();
	std::string predicate= statement.getPredicate().getName();
	std::string object= statement.getObject().getName();
	this->store_triple(subject.c_str(),predicate.c_str(),object.c_str());
}
